home *** CD-ROM | disk | FTP | other *** search
- // -------------------------------------------------------------------------------------
- // Portfolio.cxx - image Palette instance manager
- // -------------------------------------------------------------------------------------
- // Permission is granted to freely redistribute this source code, and to use fragments
- // of this code in your own applications if you find them to be useful. This class,
- // along with the source code, come with no warranty of any kind, and the user assumes
- // all responsibility for its use.
- // -------------------------------------------------------------------------------------
-
- extern "Objective-C" {
- #import <objc/objc.h>
- #import <appkit/appkit.h>
- #import <libc.h>
- #import <stdlib.h>
- #import <stdio.h>
- #import <string.h>
- #import <math.h>
- #import <sys/types.h>
- #import <sys/stat.h>
- #import <sys/time.h>
- #import <defaults/defaults.h>
- #import <dpsclient/psops.h>
- #import <dpsclient/dpsNeXT.h>
- #import "fileUtils.h"
- #import "threadStdio.h"
- }
-
- #import "ExpandImage.h"
- #import "PaletteCell.h"
- #import "PaletteMatrix.h"
- #import "Portfolio.h"
- #import "ImagePortfolio.h"
-
- // -------------------------------------------------------------------------------------
-
- /* static image ids */
- static id openFolder = (id)nil;
- static id closedFolder = (id)nil;
- static id multiFile = (id)nil;
- static id stopIcon = (id)nil;
-
- /* list of instantiated windows */
- static id instanceList = (id)nil;
-
- /* main window location scale */
- static NXPoint winPosScale = { 0.20, 0.85 };
- static NXSize winOffset = { 64.0, -24.0 };
-
- // -------------------------------------------------------------------------------------
- // static selectors
- extern "Objective-C" {
- static SEL sel_sizeToCells = @selector(sizeToCells);
- static SEL sel_setDocEdited = @selector(setDocEdited:);
- static SEL sel_loadComplete = @selector(_loadComplete);
- static SEL sel_showLargeImage = @selector(showLargeImage:);
- static SEL sel_resignActivePortfolio = @selector(resignActivePortfolio:);
- static SEL sel_doLoad = @selector(_doLoad:);
- static SEL sel_performClose = @selector(performClose:);
- static SEL sel_dirList = @selector(_loadParseString:fromFile:);
- static SEL sel_portfolioList = @selector(_loadParseString:fromPortfolio:);
- }
-
- // -------------------------------------------------------------------------------------
- // misc defines
- #define isSHIFT(S) ((([NXApp currentEvent]->flags) & (S))? YES : NO)
- #define isLOADING ([iconButtonId altImage] == stopIcon)
- #define dftCellROWS 1
- #define dftCellCOLUMNS 5
- #define dftFormatNAME "PortfolioFormat"
- #define X origin.x
- #define Y origin.y
- #define W size.width
- #define H size.height
-
- // -------------------------------------------------------------------------------------
- // rint()
- #ifdef rint_bug_fixed
- #define RINT(X) rint(X)
- #else
- inline double RINT(double x) { return copysign(floor(copysign(x,(double)1.0)+0.5),x); }
- #endif rint_bug_fixed
-
- // -------------------------------------------------------------------------------------
- // PasteBoard dragging operation variables
- extern BOOL pbDragFilesOk;
- extern NXAtom pbTypes[];
- extern int pbNumTypes;
- extern int pbChangeCount;
-
- // -------------------------------------------------------------------------------------
- @implementation Portfolio
-
- // -------------------------------------------------------------------------------------
- // internal support
-
- /* return first instance */
- + firstInstance
- {
- return (instanceList && [instanceList count])? [instanceList objectAt:0]: (id)nil;
- }
-
- // -------------------------------------------------------------------------------------
- // internal support
-
- /* (re)adjust window size to fit cell size */
- - _adjustPreference:(char*)prefBuff
- {
- int rows, cols;
- NXSize winSize, *cellSize, *gap;
- NXRect fRect;
- BOOL rtn;
-
- /* check for allowable preference adjustment */
- if (!adjustPreferences) return (id)nil;
-
- /* free preference buffer and check for successful */
- rtn = [iconMatrix setPreferences:prefBuff returnRows:&rows cols:&cols];
- if (!rtn) return self;
-
- /* calculate minimum window size */
- cellSize = [iconMatrix cellSize];
- gap = [iconMatrix intercell];
- [self getWindowSize:&winSize forCellSize:cellSize gap:gap rows:rows cols:cols];
- [paletteWindow getFrame:&fRect];
- fRect.Y += fRect.H - winSize.height;
- fRect.size = winSize;
-
- /* resize and re-display window */
- [paletteWindow placeWindow:&fRect];
- [self windowDidResize:paletteWindow];
- [paletteWindow display];
- [paletteWindow makeKeyAndOrderFront:(id)nil];
-
- return self;
- }
-
- /* (main thread only) return file type */
- - (int)_fileType:(const char*)fileName
- {
- if (XFileIsDirectory(fileName)) return 2;
- if (XFileExists(fileName)) return 1;
- return 0;
- }
-
- /* (main thread only) load ParseString from file/directory */
- - _loadParseString:(ParseString*)ps fromFile:(const char*)dirName
- {
- *ps <<= dirName;
- return self;
- }
-
- /* (main thread only) load ParseString from portfolio doc */
- - _loadParseString:(ParseString*)ps fromPortfolio:(const char*)fileName
- {
- char name[MAXPATHLEN + 1];
- FILE *fNum;
-
- /* return if no file name, or if file can't be openned */
- if (!fileName || !(fNum=fopen(fileName,"r"))) return (id)nil;
-
- /* read image paths from file */
- for (*name = 0; fgets(name, sizeof(name) - 1, fNum);) {
- if (*name == ':') [self _adjustPreference:name + 1];
- else *ps += name;
- }
- fclose(fNum);
-
- return self;
- }
-
- /* set icon button image */
- - _setFileIcon:imageId
- {
- if (imageId) [iconButtonId setAltImage:imageId];
- [iconButtonId setImage:[iconButtonId altImage]];
- return self;
- }
-
- /* set window title from file name */
- - _setWindowTitle:(char*)fileName
- {
-
- /* set last file path */
- if (fileName) {
- char path[MAXPATHLEN + 1], *p;
- strcpy(path, fileName);
- if (p = rindex(path, '/')) *p = 0; else *path = 0;
- [NXApp setLastPath:path];
- [paletteWindow setTitleAsFilename:fileName];
- } else {
- char name[MAXPATHLEN + 1];
- int len = strlen(strcpy(name, [NXApp lastPath]));
- strcat(name, ((!len||(name[len-1]!='/'))?"/UNTITLED":"UNTITLED"));
- [paletteWindow setTitleAsFilename:name];
- }
-
- return self;
- }
-
- /* make save panel */
- - _savePanel:(char*)title :(char*)extn
- {
- id savePanel = [SavePanel new];
- [savePanel setTitle:title];
- [savePanel setPrompt:"File:"];
- [savePanel setRequiredFileType:extn];
- [savePanel setDirectory:[NXApp lastPath]];
- return savePanel;
- }
-
- /* (load thread) recursive add directory to image list */
- - _addDirectory:(char*)dirPath :(BOOL)chkExtn
- {
- if (abortLoad) return (id)nil;
- switch ((int)[self mainThreadPerform:@selector(_fileType:) with:(id)dirPath wait:YES]) {
- case 2: // directory
- {
- ParseString fp;
- [self mainThreadPerform:sel_dirList with:(id)&fp with:(id)dirPath wait:YES];
- for (int i = 0; !abortLoad && fp[i]; i++) {
- char filePath[MAXPATHLEN + 1];
- sprintf(filePath, "%s/%s", dirPath, fp[i]);
- [self _addDirectory:filePath :chkExtn];
- }
- }
- return self;
- case 1: // file
- {
- if (chkExtn && ![PaletteCell validExtension:dirPath]) return (id)nil;
- [iconMatrix addImage:dirPath];
- }
- return self;
- }
- return (id)nil;
- }
-
- /* (load thread) load from doc file */
- - _loadDocument:(char*)fileName :(BOOL)checkExtension
- {
- ParseString fp;
- [self mainThreadPerform:sel_portfolioList with:(id)&fp with:(id)fileName wait:YES];
- for (int i = 0; !abortLoad && fp[i]; i++) [self _addDirectory:fp[i] :checkExtension];
- [iconMatrix mainThreadPerform:sel_sizeToCells wait:NO];
- return self;
- }
-
- /* (load thread) load file list */
- - _doLoad:(fileLIST*)fileList
- {
- fileLIST *fl, *next;
-
- /* return if no list */
- if (!fileList) return self;
-
- /* initial load lock */
- for (fl = fileList; fl;) {
-
- /* continue loading if not stopped */
- if (!abortLoad) {
- int i;
- BOOL quit, chkExt, setEdit;
-
- /* load list of images */
- chkExt = (fl->flags & 2)?YES:NO;
- setEdit = (fl->flags & 1)?NO:YES;
- for (quit = NO, i = 0; !abortLoad && !quit && (fl->list[i]); i++) {
- char *fp = fl->list[i];
- if (!strcmp(XFileExtension(fp)+1,docEXTENSION)) [self _loadDocument:fp:NO];
- else [self _addDirectory:fp:chkExt];
- }
-
- /* set window edited icon (setEdit only true on the first fileLIST loaded) */
- [paletteWindow mainThreadPerform:sel_setDocEdited
- with:(id)((int)setEdit) wait:NO];
-
- }
-
- /* free list and move to next list of images */
- mutex_lock(loadMutex);
- next = fl->next;
- delete fl;
- fl = next;
- if (!fl) loadList = (fileLIST*)nil;
- adjustPreferences = NO; // preference adjustment allowed on 1st list only
- mutex_unlock(loadMutex);
-
- }
-
- /* loading complete */
- [self mainThreadPerform:sel_loadComplete wait:NO];
- return self;
-
- }
-
- /* invoked by load thread when loading is complete */
- - _loadComplete
- {
- mutex_lock(loadMutex);
- if (!loadList) { // make sure another load hasn't been requested
- abortLoad = YES;
- [self _setFileIcon:closedFolder];
- [iconMatrix resizeAndDisplay];
- }
- mutex_unlock(loadMutex);
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // create a new instance
-
- /* general initialization */
- - init
- {
- return [self initFromList:(ParseString*)nil];
- }
-
- /* initialize and open file name */
- - initFromList:(const ParseString*)fileNames
- {
- return [self initFromList:fileNames registerWindow:YES];
- }
-
- /* initialize and open file name */
- - initFromList:(const ParseString*)fileNames registerWindow:(BOOL)regWindow
- {
- id docView;
- int rows, cols;
- const char *dftFmt;
- NXSize cellSize, scrnSize, gap, clipSize;
- NXRect docFrame, winRect;
- static int winCount = 0;
-
- /* initialize static vars */
- if (!openFolder ) openFolder = [NXImage findImageNamed:"openFolder" ];
- if (!closedFolder) closedFolder = [NXImage findImageNamed:"closedFolder"];
- if (!multiFile ) multiFile = [NXImage findImageNamed:"multiFile" ];
- if (!stopIcon ) stopIcon = [NXImage findImageNamed:"stop" ];
- if (!instanceList) instanceList = listALLOC(1);
-
- /* init super and add myself to the list of active instances */
- [super init];
- [instanceList addObject:self];
- [self resignActivePortfolio:self];
-
- /* load nib */
- [NXApp loadNibSection:"Portfolio.nib" owner:self];
-
- /* clear expanded image panel */
- expandImage = (id)nil;
-
- /* set icon button to send message on mouse down */
- fileIcon = (id)nil;
- [iconButtonId setType:NX_MOMENTARYPUSH];
- [iconButtonId setIconPosition:NX_ICONONLY];
- [iconButtonId sendActionOn:NX_MOUSEDOWNMASK];
- [[iconButtonId setTarget:self] setAction:@selector(iconDrag:)];
- [self _setFileIcon:closedFolder];
-
- /* file name load list flags */
- abortLoad = YES;
- loadMutex = mutex_alloc();
- loadList = (fileLIST*)nil;
-
- /* make a new matrix */
- docView = [paletteScroll docView];
- [docView getFrame:&docFrame];
- [docView getCellSize:&cellSize];
- iconMatrix = [[PaletteMatrix alloc] initFrame:&docFrame];
- [iconMatrix setCellSize:&cellSize];
- [iconMatrix setFont:[[docView cellAt:0:0] font]];
- [iconMatrix setDelegate:self];
- [iconMatrix setTarget:self];
- [iconMatrix setDoubleAction:sel_showLargeImage];
- [iconMatrix setSelectionByRect:YES];
- [paletteScroll setDocView:iconMatrix];
- [paletteScroll setPageScroll:0.0]; // full page scrolling
- [[paletteScroll setHorizScroller:(id)nil] free]; // remove the horiz scroller
- [docView free]; // free the old view
-
- /* defaults */
- dftFmt = NXReadDefault([NXApp appName], dftFormatNAME);
- if (![iconMatrix setPreferences:(char*)dftFmt returnRows:&rows cols:&cols]) {
- rows = dftCellROWS;
- cols = dftCellCOLUMNS;
- }
-
- /* calculate new window size and location */
- cellSize = *[iconMatrix cellSize]; // re-read cellSize
- gap = *[iconMatrix intercell];
- [NXApp getScreenSize:&scrnSize];
- [self getWindowSize:&winRect.size forCellSize:&cellSize gap:&gap rows:rows cols:cols];
- winRect.X = floor(scrnSize.width *winPosScale.x)+((float)winCount*winOffset.width );
- winRect.Y = floor(scrnSize.height*winPosScale.y)+((float)winCount*winOffset.height);
- if (winRect.X > (scrnSize.width - 64.0)) winRect.X = scrnSize.width - 64.0;
- if (winRect.Y > (scrnSize.height - 24.0)) winRect.Y = scrnSize.height - 24.0;
- winRect.Y -= winRect.H;
- winCount = (++winCount) % 5;
-
- /* reposition window */
- [paletteWindow placeWindow:&winRect];
- [self windowDidResize:paletteWindow];
- [paletteScroll getContentSize:&clipSize];
- windowOverhead.width = winRect.W - clipSize.width ;
- windowOverhead.height = winRect.H - clipSize.height;
-
- /* clear window header statistics */
- [self cellResignedSelected:(id)nil];
-
- /* register window */
- isRegistered = NO;
- allowDrop = regWindow;
- [self _registerWindow];
- [paletteWindow setDelegate:self];
- [paletteWindow setMiniwindowIcon:"doc"];
- [paletteWindow addToEventMask:NX_MOUSEENTEREDMASK];
-
- /* calculate absolute minimum window size */
- minCellSize.width = 70.0;
- minCellSize.height = 40.0;
- [self getWindowSize:&minWindowSize forCellSize:&minCellSize gap:&gap rows:1 cols:1];
-
- /* load file if specified */
- adjustPreferences = YES;
- sourceFile = (char*)nil;
- if (((void*)fileNames) && (*fileNames)[0]) {
- BOOL isDoc = ((fileNames->count() > 1) ||
- strcmp(XFileExtension((*fileNames)[0]), dotDocEXTENSION))? NO : YES;
- if (isDoc) sourceFile = NXCopyStringBuffer((*fileNames)[0]);
- [self loadFileList:fileNames :isDoc:!isDoc];
- }
- [self _setWindowTitle:sourceFile];
-
- /* make window key */
- [paletteWindow display];
- [paletteWindow makeKeyAndOrderFront:(id)nil];
-
- return self;
- }
-
- /* free image Palette window manager */
- - free
- {
- [paletteWindow free];
- if (expandImage) { [expandImage free]; expandImage = (id)nil; }
- if (fileIcon) { [fileIcon free]; fileIcon = (id)nil; }
- if (sourceFile) { free(sourceFile); sourceFile = (char*)nil; }
- mutex_free(loadMutex);
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // active portfolio delegate
-
- /* become active portfolio */
- - becomeActivePortfolio:sender
- {
- isActivePortfolio = YES;
- [paletteWindow becomeMainWindow];
- return self;
- }
-
- /* resign active portfolio */
- - resignActivePortfolio:sender
- {
- isActivePortfolio = NO;
- return self;
- }
-
- /* return true if active */
- - (BOOL)isActivePortfolio
- {
- return isActivePortfolio;
- }
-
- /* make portfolio active */
- + makeActivePortfolio:(Portfolio*)portObj
- {
- [instanceList makeObjectsPerform:sel_resignActivePortfolio with:(id)nil];
- [portObj becomeActivePortfolio:(id)nil];
- return self;
- }
-
- /* return active portfolio */
- + activePortfolio
- {
- id pObj = (id)nil;
- int i = [instanceList count];
- while(i) if ([(pObj = [instanceList objectAt:--i]) isActivePortfolio]) break;
- return pObj;
- }
-
- // -------------------------------------------------------------------------------------
- // document status
-
- /* return true if there are any unsaved files */
- + (BOOL)isDocEdited
- {
- int i = [instanceList count];
- while(i) if ([[instanceList objectAt:--i] isDocEdited]) return YES;
- return NO;
- }
-
- /* return true if this document has been edited */
- - (BOOL)isDocEdited
- {
- return [paletteWindow isDocEdited];
- }
-
- /* return true if loading new images (main thread only!) */
- - (BOOL)isLoading
- {
- return isLOADING;
- }
-
- // -------------------------------------------------------------------------------------
- // font
-
- /* return matrix font */
- - font
- {
- return [iconMatrix font];
- }
-
- /* change font */
- - setFont:fontObj
- {
- [iconMatrix setFont:fontObj];
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // button methods
-
- /* show Palette window */
- - show:sender
- {
- [paletteWindow display];
- [paletteWindow makeKeyAndOrderFront:(id)nil];
- return self;
- }
-
- /* open file */
- - open:sender
- {
- return self;
- }
-
- /* save file names (called by first responder) */
- - save:sender
- {
-
- /* get file name to save */
- if (!sourceFile) {
- const char *temp;
- id pSave = [self _savePanel:"Save Image Palette" :docEXTENSION];
- if (![pSave runModalForDirectory:[NXApp lastPath] file:""]) return self;
- if (!(temp=[pSave filename])) return self;
- sourceFile = NXCopyStringBuffer(temp);
- }
-
- /* open , write data, and close */
- [iconMatrix saveToFile:sourceFile];
- [self _setWindowTitle:sourceFile];
-
- return self;
- }
-
- /* save file names (called by first responder) */
- - saveAs:sender
- {
- if (sourceFile) { free(sourceFile); sourceFile = (char*)nil; }
- return [self save:sender];
- }
-
- /* save defaults */
- - saveDefaults:sender
- {
- char buff[512];
- NXWriteDefault([NXApp appName], dftFormatNAME, [iconMatrix getPreferenceString:buff]);
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // calculate window size overhead
- // - This method needs to know the layout of the screen to properly calculate its size
-
- - getWindowSize:(NXSize*)windowSize forCellSize:(NXSize*)cellSize gap:(NXSize*)gapSize
- rows:(int)rows cols:(int)cols
- {
- NXRect fRect, cRect;
- NXSize actualSize;
-
- /* calculate actual size of content area */
- actualSize.width = (cellSize->width + gapSize->width ) * cols;
- actualSize.height = (cellSize->height + gapSize->height) * rows;
-
- /* calc size of scrollView */
- [[paletteScroll class] getFrameSize:&cRect.size forContentSize:&actualSize
- horizScroller:([paletteScroll horizScroller]?YES:NO)
- vertScroller:([paletteScroll vertScroller]?YES:NO)
- borderType:[paletteScroll borderType]];
-
- /* calc size of window contentView */
- [windowHeader getFrame:&fRect];
- cRect.H += fRect.H;
-
- /* calc window size */
- cRect.X = cRect.Y = 0.0;
- [[paletteWindow class] getFrameRect:&fRect forContentRect:&cRect
- style:[paletteWindow style]];
- *windowSize = fRect.size;
-
- return self;
- }
-
- /* get current displayed row/col count */
- - getDisplayedRows:(int*)rows cols:(int*)cols
- {
- NXSize scSize, *cellSize = [iconMatrix cellSize], *gap = [iconMatrix intercell];
- [paletteScroll getContentSize:&scSize];
- *rows = (int)RINT(scSize.height / (cellSize->height + gap->height));
- *cols = (int)RINT(scSize.width / (cellSize->width + gap->width ));
- return self;
- }
-
- /* return current cell size */
- - (NXSize*)cellSize
- {
- return [iconMatrix cellSize];
- }
-
- // -------------------------------------------------------------------------------------
- // show selected cell enlarged image (double action from matrix)
-
- /* return id to expanded image instance */
- - expandImage
- {
- if (!expandImage) expandImage = [[ExpandImage alloc] init];
- return expandImage;
- }
-
- /* matrix doubleAction */
- - showLargeImage:sender
- {
- id imageCell = [iconMatrix selectedCell];
- id expand = [self expandImage];
-
- /* hide large panel and return if no selected cell */
- [expand orderOut:self];
- if (!imageCell) return self;
-
- /* show enlarged image */
- [expand showImage:[imageCell image]:[imageCell imagePath] title:[imageCell cellTitle]];
-
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // pass file list to workspace manager
-
- /* send files to workspace manager for dragging */
- - iconDrag:sender
- {
- NXRect bFrame, rect;
- char *fullPath;
-
- /* ignore if not called by proper button */
- if (sender != iconButtonId) return self; // ignore any imposters
-
- /* check for STOP button */
- if (isLOADING) { abortLoad = YES; return self; } // stop button pressed
-
- /* ignore if no files selected */
- if (!(fullPath = [iconMatrix selectedCellPaths])) return self; // ignore if no files
-
- /* drag selected files */
- [iconButtonId getBounds:&bFrame];
- rect.W = 48.0;
- rect.H = 48.0;
- rect.X = (bFrame.W - rect.W) / 2.0;
- rect.Y = (bFrame.H - rect.H) / 2.0;
- [self _unregisterWindow]; // unregister myself
- [iconButtonId dragFile:fullPath fromRect:&rect slideBack:YES event:[NXApp currentEvent]];
- [self _registerWindow]; // re-register myself
-
- /* free file list */
- free(fullPath);
-
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // PaletteMatrix delegate methods
-
- /* (main thread) load file string list */
- - loadFileString:(const char*)fileString :(BOOL)openDoc :(BOOL)chkExtn
- {
- if (!fileString || !*fileString) return self;
- ParseString ft = fileString;
- return [self loadFileList:&ft :openDoc :chkExtn];
- }
-
- /* (main thread) load file list table */
- - loadFileList:(const ParseString*)fileNames :(BOOL)openDoc :(BOOL)chkExtn
- {
- fileLIST *fl;
-
- /* return if no files to load */
- if (!((void*)fileNames) || !(*fileNames)[0]) return self;
-
- /* allocate and fill file list structure */
- fl = new fileLIST;
- fl->list = *fileNames;
- fl->flags = (chkExtn?2:0) | (openDoc?1:0);
- fl->next = (fileLIST*)nil;
-
- /* load images (fork new thread if necessary) */
- mutex_lock(loadMutex);
- if (loadList) loadList->next = fl; // load already in progress
- else {
- abortLoad = NO; // reset abort flag
- [self _setFileIcon:stopIcon]; // setup stop button
- [iconMatrix clearSelectedCell]; // deselect any selected cells
- [self forkPerform:sel_doLoad with:(id)fl detach:YES];
- }
- loadList = fl;
- mutex_unlock(loadMutex);
-
- return self;
- }
-
- /* set image statistics (only called when a cell is (de)selected) */
- - clearImageStats:iconImage // 'closedFolder' or 'multiFile' only
- {
- [iconPathId setStringValue:""];
- [iconSizeId setStringValue:""];
- [self _setFileIcon:iconImage];
- return self;
- }
-
- /* set image statistics */
- - setImageStats:imageCell
- {
- NXRect bBox;
- char buff[256];
-
- /* clear stats if no cell */
- if (!imageCell) { [self clearImageStats:closedFolder]; return self; }
-
- /* fill info */
- [iconPathId setStringValueNoCopy:[imageCell imagePath]];
- [[imageCell image] getSize:&bBox.size];
- sprintf(buff, "%.0f x %.0f", bBox.W, bBox.H);
- [iconSizeId setStringValue:buff];
-
- /* set icon representation */
- if (fileIcon) [fileIcon free];
- fileIcon = [[Application workspace] getIconForFile:(char*)[imageCell imagePath]];
- [self _setFileIcon:fileIcon];
-
- return self;
- }
-
- /* image became selected */
- - cellBecameSelected:imageCell
- {
- if (expandImage) [expandImage orderOut:self]; // hide large panel
- if ([iconMatrix selectedCellCount] <= 1) [self setImageStats:imageCell];
- else [self clearImageStats:multiFile];
- return self;
- }
-
- /* image became selected */
- - cellResignedSelected:imageCell
- {
- if ([iconMatrix selectedCellCount] > 1) [self clearImageStats:multiFile];
- else [self setImageStats:[iconMatrix selectedCell]];
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // Workspace manager icon dragging support
- // Note: The static variables declared here are acceptable since only one drag operation
- // can occur at any given time.
-
- /* register window with workspace manager */
- - _registerWindow
- {
- if (!allowDrop || isRegistered) return self;
- [paletteWindow registerForDraggedTypes:pbTypes count:pbNumTypes];
- isRegistered = YES;
- return self;
- }
-
- /* unregister window with workspace manager */
- - _unregisterWindow
- {
- if (!allowDrop || !isRegistered) return self;
- [paletteWindow unregisterDraggedTypes];
- isRegistered = NO;
- return self;
- }
-
- /* file icon entered */
- - (NXDragOperation)draggingEntered:sender
- {
- Pasteboard *pb = [sender draggingPasteboard];
- pbDragFilesOk = YES;
- if (![pb findAvailableTypeFrom:pbTypes num:pbNumTypes]) pbDragFilesOk = NO; else
- if (pbChangeCount == [pb changeCount]) pbDragFilesOk = NO;
- if (pbDragFilesOk) { [iconButtonId setImage:openFolder]; return NX_DragOperationCopy; }
- return NX_DragOperationNone;
- }
-
- /* file icon moved to location */
- - (NXDragOperation)draggingUpdated:sender
- {
- return pbDragFilesOk? NX_DragOperationCopy : NX_DragOperationNone;
- }
-
- /* file icon exited */
- // - reset the open file folder icon
- - draggingExited:sender
- {
- [self _setFileIcon:(id)nil];
- pbDragFilesOk = NO;
- return self;
- }
-
- /* indicate we accept dragging */
- - (BOOL)prepareForDragOperation:sender
- {
- return pbDragFilesOk? YES : NO;
- }
-
- /* files dropped */
- - (BOOL)performDragOperation:sender
- {
- char *fileList;
- int fileListLen;
- Pasteboard *pb = [sender draggingPasteboard];
- [self _setFileIcon:(id)nil];
- if (pbDragFilesOk && [pb readType:pbTypes[0] data:&fileList length:&fileListLen]) {
- ParseString dragFiles = fileList;
- [pb deallocatePasteboardData:fileList length:fileListLen];
- pbChangeCount = [pb changeCount];
- pbDragFilesOk = NO;
- if (dragFiles[0]) {
- [NXApp activateSelf:YES];
- [paletteWindow makeKeyAndOrderFront:(id)nil];
- [self loadFileList:&dragFiles:NO:(isSHIFT(NX_CONTROLMASK)?NO:YES)];
- return YES;
- }
- }
- return NO;
- }
-
- /* clean up */
- - concludeDragOperation:sender
- {
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // window delegate methods
-
- /* window is resizing */
- - windowWillResize:windowId toSize:(NXSize*)newSize
- {
- float rows, cols, mRow, mCol;
- NXSize size, minSize, oneCellSize;
- NXSize *cellSize = [iconMatrix cellSize], *gap = [iconMatrix intercell];
-
- /* actual cell size */
- oneCellSize = *cellSize;
- oneCellSize.width += gap->width ;
- oneCellSize.height += gap->height;
-
- /* absolute minimum size */
- if (newSize->width < minWindowSize.width ) newSize->width = minWindowSize.width ;
- if (newSize->height < minWindowSize.height) newSize->height = minWindowSize.height;
-
- /* allow any window size if Alternate is pressed */
- if (isSHIFT(NX_ALTERNATEMASK)) {
- if (isLOADING) { // retain original size
- NXRect wFrame;
- [windowId getFrame:&wFrame];
- *newSize = wFrame.size;
- return self;
- }
- [paletteScroll getContentSize:&size];
- cols = size.width / oneCellSize.width ;
- rows = size.height / oneCellSize.height;
- minSize.width = RINT((minCellSize.width +gap->width )*cols)+windowOverhead.width ;
- minSize.height = RINT((minCellSize.height+gap->height)*rows)+windowOverhead.height;
- if (newSize->width < minSize.width ) newSize->width = minSize.width;
- if (newSize->height < minSize.height) newSize->height = minSize.height;
- return self;
- }
-
- /* window size must hold at least one cell */
- minSize.width = windowOverhead.width + oneCellSize.width ;
- minSize.height = windowOverhead.height + oneCellSize.height;
- if (newSize->width < minSize.width ) newSize->width = minSize.width ;
- if (newSize->height < minSize.height) newSize->height = minSize.height;
-
- /* size window to cell boundary */
- cols = RINT((newSize->width - windowOverhead.width ) / oneCellSize.width );
- rows = RINT((newSize->height - windowOverhead.height) / oneCellSize.height);
- mCol = ceil((minWindowSize.width - windowOverhead.width ) / oneCellSize.width );
- mRow = ceil((minWindowSize.height - windowOverhead.height) / oneCellSize.height);
- if (cols < mCol) cols = mCol;
- if (rows < mRow) rows = mRow;
- newSize->width = windowOverhead.width + cols * oneCellSize.width ;
- newSize->height = windowOverhead.height + rows * oneCellSize.height;
-
- return self;
- }
-
- /* window is resizing */
- - windowDidResize:windowId
- {
- float oldRows, oldCols;
- NXRect sFrame, matFrame, winFrame;
- NXSize scSize, *cellSize = [iconMatrix cellSize], *gap = [iconMatrix intercell];
-
- /* ignore if loading is in progress */
- if (isSHIFT(NX_ALTERNATEMASK) && isLOADING) return self;
-
- /* get new window size */
- [[windowId contentView] getFrame:&winFrame];
-
- /* reposition header */
- [windowHeader getFrame:&sFrame];
- winFrame.H -= sFrame.H;
- sFrame.Y = winFrame.H;
- sFrame.W = winFrame.W;
- [windowHeader setFrame:&sFrame];
- headerSize = sFrame.size;
-
- /* resize iconPathId text field */
- [iconPathId getFrame:&sFrame];
- sFrame.W = headerSize.width - sFrame.X;
- [iconPathId setFrame:&sFrame];
-
- /* save current number of displayed rows/cols */
- [paletteScroll getContentSize:&scSize];
- oldCols = scSize.width / (cellSize->width + gap->width );
- oldRows = scSize.height / (cellSize->height + gap->height);
-
- /* resize scroller */
- [paletteScroll getFrame:&sFrame];
- sFrame.size = winFrame.size;
- sFrame.Y = 0.0;
- sFrame.X = 0.0;
- [paletteScroll setFrame:&sFrame];
-
- /* resize matrix within scroller */
- [paletteScroll getContentSize:&scSize];
- [iconMatrix getFrame:&matFrame];
- matFrame.size = scSize;
- [iconMatrix setFrame:&matFrame];
-
- /* if alternate key is pressed, then resize cells */
- if (isSHIFT(NX_ALTERNATEMASK)) {
- NXSize size;
- size.width = RINT(matFrame.W / oldCols) - gap->width;
- size.height = RINT(matFrame.H / oldRows) - gap->height;
- [iconMatrix setCellSize:&size];
- }
-
- /* size matrix view to fit cells */
- [iconMatrix sizeToCells];
-
- return self;
- }
-
- /* window will close */
- - windowWillClose:windowId
- {
-
- /* delay window close if still loading */
- abortLoad = YES;
- if (isLOADING) {
- [windowId perform:sel_performClose with:self afterDelay:250 cancelPrevious:NO];
- return (id)nil;
- }
-
- /* check for saved */
- if ([windowId isDocEdited]) {
- int rtn;
- const char *save, *no, *cncl, *savf;
- save = NXLocalizedString("Save", (char*)nil,(char*)nil);
- no = NXLocalizedString("No", (char*)nil,(char*)nil);
- cncl = NXLocalizedString("Cancel", (char*)nil,(char*)nil);
- if (sourceFile) {
- char name[MAXPATHLEN + 1], *p;
- strcpy(name, XFileNameExtension(sourceFile));
- if (p = rindex(name, '.')) *p = 0;
- savf = NXLocalizedString("Save changes to %s?", (char*)nil,(char*)nil);
- rtn = NXRunAlertPanel(save, savf, save, no, cncl, name);
- } else {
- savf = NXLocalizedString("Save changes to UNTITLED?", (char*)nil,(char*)nil);
- rtn = NXRunAlertPanel(save, savf, save, no, cncl);
- }
- if (rtn == NX_ALERTOTHER) return (id)nil; // Cancel
- if (rtn == NX_ALERTDEFAULT) [self save:(id)nil]; // Save (else No)
- }
-
- /* unregister / remove / and free */
- [self _unregisterWindow];
- [instanceList removeObject:self];
- return [NXApp delayedFree:self];
-
- }
-
- /* window became key */
- - windowDidBecomeKey:windowId
- {
- [[self class] makeActivePortfolio:self];
- [windowId makeFirstResponder:iconMatrix];
- [[FontManager new] setSelFont:[iconMatrix font] isMultiple:NO];
- return self;
- }
-
- @end
-